import base64
import os
from typing import Dict, Any#是一个封装了百度AI开放平台身份证OCR服务的工具类

import requests
from fastapi import HTTPException
# 密钥配置管理
try:
    from config.baidu_config import BAIDU_API_KEY as CFG_API_KEY, BAIDU_SECRET_KEY as CFG_SECRET_KEY
except Exception:
    CFG_API_KEY, CFG_SECRET_KEY = "", ""

# 本地常量兜底（开发调试用，不建议生产直接写）
LOCAL_BAIDU_API_KEY = "1HLNKZflj96F0bPuCuYJRTFy"
LOCAL_BAIDU_SECRET_KEY = "Ls2ITjdEaDMZol6Qo2oGehXImn3hCcrK"


class BaiduOCR:
    """
    百度身份证OCR工具
    读取顺序：环境变量 → config/baidu_config.py → 本地常量
    """

    TOKEN_URL = "https://aip.baidubce.com/oauth/2.0/token"
    IDCARD_URL = "https://aip.baidubce.com/rest/2.0/ocr/v1/idcard"

    @classmethod
    def _get_keys(cls) -> Dict[str, str]:#获取百度 AI 开放平台的 API 密钥和密钥（API Key、Secret Key）
        # 1) 环境变量
        env_api = os.getenv("BAIDU_API_KEY")
        env_secret = os.getenv("BAIDU_SECRET_KEY")
        # 2) 配置文件兜底
        api_key = env_api or CFG_API_KEY or LOCAL_BAIDU_API_KEY
        secret_key = env_secret or CFG_SECRET_KEY or LOCAL_BAIDU_SECRET_KEY
        if not api_key or not secret_key:
            raise HTTPException(
                status_code=500,
                detail="缺少百度OCR密钥配置：请设置环境变量或在config/baidu_config.py或utils/baidu_ocr.py中提供密钥",
            )
        return {"api_key": api_key, "secret_key": secret_key}

    @classmethod
    def get_access_token(cls) -> str:#获取令牌
        keys = cls._get_keys()
        params = {
            "grant_type": "client_credentials",
            "client_id": keys["api_key"],
            "client_secret": keys["secret_key"],
        }
        try:
            resp = requests.get(cls.TOKEN_URL, params=params, timeout=8)
            data = resp.json()
            token = data.get("access_token")
            if not token:
                raise HTTPException(status_code=502, detail=f"获取百度Token失败: {data}")
            return token
        except HTTPException:
            raise
        except Exception as e:
            raise HTTPException(status_code=502, detail=f"获取百度Token异常: {str(e)}")

    @classmethod
    def idcard_ocr(cls, image_path: str, side: str = "front") -> Dict[str, Any]:#上传身份证图片，识别身份证信息
        if side not in ("front", "back"):
            raise HTTPException(status_code=400, detail="id_card_side参数必须为front或back")
        try:
            with open(image_path, "rb") as f:
                img_b64 = base64.b64encode(f.read())
        except Exception:
            raise HTTPException(status_code=400, detail="图片读取失败")

        token = cls.get_access_token()
        url = f"{cls.IDCARD_URL}?access_token={token}"
        headers = {"Content-Type": "application/x-www-form-urlencoded"}
        data = {
            "image": img_b64,
            "id_card_side": side,
            "detect_direction": "true",
        }
        try:
            resp = requests.post(url, data=data, headers=headers, timeout=10)
            result = resp.json()
            if result.get("error_code"):
                raise HTTPException(status_code=400, detail=f"OCR错误: {result.get('error_msg')}")
            return result
        except HTTPException:
            raise
        except Exception as e:
            raise HTTPException(status_code=502, detail=f"调用百度OCR异常: {str(e)}")

    @staticmethod
    def extract_front_fields(result: Dict[str, Any]) -> Dict[str, Any]:#解析正面身份证信息
        words = result.get("words_result", {})
        def w(key: str) -> str:
            return (words.get(key) or {}).get("words", "")
        name = w("姓名")
        id_no = w("公民身份号码")
        address = w("住址")
        if not name or not id_no:
            raise HTTPException(status_code=400, detail="未识别出姓名或身份证号")
        if len(id_no) != 18:
            raise HTTPException(status_code=400, detail="身份证号格式不正确")
        return {
            "name": name,
            "id_number": id_no,
            "address": address,
            "birth": w("出生"),
            "nation": w("民族"),
        }
